/*******************************************************************************
 * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *******************************************************************************/
package de.itemis.gmf.runtime.edit.policy;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.diagram.ui.editpolicies.CanonicalConnectionEditPolicy;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Edge;
import org.eclipse.gmf.runtime.notation.View;

/**
 * A new superclass for the canonical diagram edit policy generated by GMF.
 * Allows to manually add edges.
 * 
 * @author koehnlein
 */
public abstract class SemiCanonicalDiagramEditPolicy extends
		CanonicalConnectionEditPolicy {

	/*
	 * Additional public API
	 */
	public static final String SEMI_CANONICAL_ROLE = "SemiCanonicalRole";

	@SuppressWarnings("unchecked")
	public void addConnections(Collection<EObject> connectableSemanticElements) {
		Diagram diagram = ((View) getHost().getModel()).getDiagram();
		HashMap domain2NotationMap = new HashMap();
		Collection allLinks = collectAllLinks(diagram, domain2NotationMap);
		removeExistingAndIrrelevantLinks(allLinks, connectableSemanticElements,
				diagram);
		createConnections(allLinks, domain2NotationMap);
	}

	/*
	 * Methods generated by GMF. Change visibility in template
	 */
	@SuppressWarnings("unchecked")
	protected abstract Collection collectAllLinks(View view,
			Map domain2NotationMap);

	@SuppressWarnings("unchecked")
	protected abstract Collection createConnections(Collection linkDescriptors,
			Map domain2NotationMap);

	/*
	 * Methods to be implemented in generated code as they refer to the
	 * statically typed classes XXXLinkDescriptor and XXXVisualIDRegistry.
	 */

	protected abstract boolean isLinkSourceInList(Object linkDescriptor,
			Collection<EObject> connectableElements);

	protected abstract boolean isLinkTargetInList(Object linkDescriptor,
			Collection<EObject> connectableElements);

	protected abstract boolean isDescriptorMatchesEdge(Object linkDescriptor,
			Edge edge);

	/*
	 * Internal stuff
	 */
	@SuppressWarnings("unchecked")
	private Collection removeExistingAndIrrelevantLinks(Collection allLinks,
			Collection<EObject> selectedSemanticElements, Diagram diagram) {
		EList existingConnections = diagram.getEdges();
		ALL_LINKS: for (Iterator iterator = allLinks.iterator(); iterator
				.hasNext();) {
			Object linkDescriptor = iterator.next();
			if (!isLinkSourceInList(linkDescriptor, selectedSemanticElements)
					&& !isLinkTargetInList(linkDescriptor,
							selectedSemanticElements)) {
				iterator.remove();
				continue ALL_LINKS;
			}

			for (Object existingConnection : existingConnections) {
				if (isDescriptorMatchesEdge(linkDescriptor,
						(Edge) existingConnection)) {
					iterator.remove();
					continue ALL_LINKS;
				}
			}
		}
		return allLinks;
	}

}
